#ifndef _INTERPRETER_H
#define _INTERPRETER_H

#include "Types.h"
#include <vector>
#include <stack>
#include <deque>
#include <hash_map>

enum OPCODE : u32
{
#undef BB
#define BB(xx) OP_##xx,
#include "Opcode.h"
};

static const char* g_Opcode[] = {
#undef BB
#define BB(xx) #xx,
#include "Opcode.h"
};

struct ByteCode
{
  OPCODE      opcode;
  Value       v;
};

class CInterpreter
{
public:
  CInterpreter();

public:
  size_t  Generate(ByteCode& code);
  void    FixJMP(size_t pc, size_t dst);
  void    Run();
  void    Execute(ByteCode& code);

  void    Reset();
  void    Pause();
  void    Resume();

private:
#define BB(xx) void Handle_OP_##xx(ByteCode& code);
#include "Opcode.h"

private:
  void    CallFunction(std::string& name, std::deque<Value>& params);
  // internal functions
#define CC(xx) void xx(std::deque<Value>&);
#include "Functions.h"

private:
  std::vector<ByteCode>   m_ByteCode;
  std::stack<Value>       m_Stack;
  void                    (CInterpreter::*m_Handler[OP_MAX+1])(ByteCode&);
  std::hash_map<std::string, void (CInterpreter::*)(std::deque<Value>&)> m_InternalFunctions;
  size_t                  m_PC;
  bool                    m_Paused;
};

#endif  // _INTERPRETER_H
